﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Reflection;
using Vbyte.SharpOrm.Config;

namespace Vbyte.SharpOrm
{
    public static partial class OrmHelper
    {
        #region Update
        /// <summary>
        /// 更新到相关数据库
        /// </summary>
        /// <param name="SqlTableEntry">表映射实例</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int Update(this TableEntry SqlTableEntry)
        {
            return Update(SqlTableEntry, new string[0], null, null);
        }

        /// <summary>
        /// 更新数据库相关实例。
        /// </summary>
        /// <param name="SqlTableEntry">表映射实例</param>
        /// <param name="NotIgnoreDefaultValueProperties">强制不忽略默认值的字段集合</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int Update(this TableEntry SqlTableEntry, string[] NotIgnoreDefaultValueProperties)
        {
            return Update(SqlTableEntry, NotIgnoreDefaultValueProperties, null, null);
        }

        /// <summary>
        /// (事务支持)使用已打开的共享连接，更新数据库相关实例。
        /// </summary>
        /// <param name="SqlTableEntry">表映射实例</param>
        /// <param name="NotIgnoreDefaultValueProperties">强制不忽略默认值的字段集合</param>
        /// <param name="SharedOpenConnection">已打开的共享数据库连接，只使用不关闭及销毁。</param>
        /// <param name="trans">当前关联的数据库事务</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int Update(this TableEntry SqlTableEntry, string[] NotIgnoreDefaultValueProperties,
            DbConnection SharedOpenConnection, DbTransaction trans)
        {
            int result = 0;
            DbCommand cmd = GeneratorDbCommand(SqlTableEntry, SQLRowCommandType.Update, NotIgnoreDefaultValueProperties);
            if (trans != null) cmd.Transaction = trans;
            //Debug(cmd);
            if (SharedOpenConnection != null)
            {
                cmd.Connection = SharedOpenConnection;
                if (SharedOpenConnection.State == ConnectionState.Closed)
                {
                    SharedOpenConnection.Open();
                }
                result = cmd.ExecuteNonQuery();
            }
            else
            {
                DbConnection conn = new AdoNetAdapter(SqlTableEntry).GetDbConnection();
                conn.Open();
                cmd.Connection = conn;
                result = cmd.ExecuteNonQuery();
                conn.Close();
                conn.Dispose();
            }
            cmd.Dispose();
            return result;
        }

        /// <summary>
        /// 使用已打开的共享连接，更新数据库相关实例。
        /// </summary>
        /// <param name="SqlTableEntry">表映射实例</param>
        /// <param name="NotIgnoreDefaultValueProperties">强制不忽略默认值的字段集合</param>
        /// <param name="SharedOpenConnection">已打开的共享数据库连接，只使用不关闭及销毁。</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int Update(this TableEntry SqlTableEntry, string[] NotIgnoreDefaultValueProperties,
            DbConnection SharedOpenConnection)
        {
            return Update(SqlTableEntry, NotIgnoreDefaultValueProperties, SharedOpenConnection, null);
        }

        /// <summary>
        /// 使用已打开的共享连接，更新数据库相关实例。
        /// </summary>
        /// <param name="SqlTableEntry">表映射实例</param>
        /// <param name="SharedOpenConnection">已打开的共享数据库连接，只使用不关闭及销毁。</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int Update(this TableEntry SqlTableEntry, DbConnection SharedOpenConnection)
        {
            return Update(SqlTableEntry, new string[0], SharedOpenConnection, null);
        }

        /// <summary>
        /// (事务支持)使用已打开的共享连接，(忽略主键)依据旧有实例属性替换为新实例属性的值（更新满足条件的1个或多个记录）
        /// </summary>
        /// <param name="oldSqlTableEntry">满足实例的条件</param>
        /// <param name="newSqlTableEntry">新实例的值</param>
        /// <param name="SharedOpenConnection">已打开的共享数据库连接，只使用不关闭及销毁。</param>
        /// <param name="trans">当前关联的数据库事务</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int ReplaceWith(this TableEntry oldSqlTableEntry, TableEntry newSqlTableEntry, DbConnection SharedOpenConnection,
            DbTransaction trans)
        {

            if (oldSqlTableEntry == null || newSqlTableEntry == null)
            {
                throw new ArgumentNullException("oldSqlTableEntry", "新旧实例均不能为null！");
            } 
            Type instanceType = oldSqlTableEntry.GetType();
            if (!instanceType.Equals(newSqlTableEntry.GetType()))
            {
                throw new InvalidOperationException("新旧实例类型须为同一类型实例！");
            }
            int result = 0;
            DbCommand cmd = GeneratorDbCommand(newSqlTableEntry, SQLRowCommandType.Update);
            if (trans != null) cmd.Transaction = trans;
            string sqlCmd = cmd.CommandText;

            string whereKey = " where ";
            int whereIndex = sqlCmd.IndexOf(whereKey, StringComparison.InvariantCultureIgnoreCase);

            #region 处理成 "update [table] set a=@a,b=@b where "
            if (whereIndex != -1)
            {
                string[] oldWheres = sqlCmd.Substring(whereIndex + whereKey.Length).Split(',');
                string strTemp = "";
                int pcIndex = -1;
                foreach (string strLimit in oldWheres)
                {
                    strTemp = strLimit.Trim();
                    pcIndex = strTemp.IndexOf("@");
                    if (pcIndex != -1)
                    {
                        strTemp = strTemp.Substring(pcIndex + 1);

                        #region 取消旧的参数
                        if (cmd.Parameters.Contains(strTemp))
                        {
                            cmd.Parameters.Remove(cmd.Parameters[strTemp]);
                        }
                        #endregion
                    }
                }
                sqlCmd = sqlCmd.Substring(0, whereIndex + whereKey.Length);
            }
            else
            {
                sqlCmd += " where ";
            }
            #endregion

            #region 设置参数和cmd的条件限制
            string[] propBinds = GetInstanceBind(instanceType, oldSqlTableEntry);
            if (propBinds.Length < 1)
            {
                throw new InvalidOperationException("没能获取旧实例的限制条件！");
            }
            else
            {
                List<string> newWheres = new List<string>(propBinds.Length);
                string newPropName = "";
                foreach (string propName in propBinds)
                {
                    newPropName = propName;

                    //判定是否有映射转换
                    PropertyInfo pi = instanceType.GetProperty(propName);
                    TableItemAttribute[] itemAttr = GetMemberInfoCustomAttributes<TableItemAttribute>(pi, true);
                    if (itemAttr.Length > 0)
                    {
                        newPropName = itemAttr[0].BindField;
                    }
                    newWheres.Add(string.Format("{0}=@{1}", newPropName, "n" + propName));

                    DbParameter p = cmd.CreateParameter();
                    p.ParameterName = "n" + propName;
                    p.Value = GetInstanceProperty(instanceType, oldSqlTableEntry, propName);
                    cmd.Parameters.Add(p);
                }
                sqlCmd += string.Join(" AND ", newWheres.ToArray());
            }
            #endregion

            //更新sql命令
            cmd.CommandText = sqlCmd;
            #region 与连接关联更新
            if (SharedOpenConnection != null)
            {
                cmd.Connection = SharedOpenConnection;
                if (SharedOpenConnection.State == ConnectionState.Closed)
                {
                    SharedOpenConnection.Open();
                }
                result = cmd.ExecuteNonQuery();
            }
            else
            {
                DbConnection conn = new AdoNetAdapter(newSqlTableEntry).GetDbConnection();
                conn.Open();

                cmd.Connection = conn;
                result = cmd.ExecuteNonQuery();

                conn.Close();
                conn.Dispose();
            }

            #endregion
            //System.Diagnostics.Debug.WriteLine(cmd.Parameters.Count);
            //System.Diagnostics.Debug.WriteLine(sqlCmd);
            cmd.Dispose();
            return result;

        }

        /// <summary>
        /// 使用已打开的共享连接，(忽略主键)依据旧有实例属性替换为新实例属性的值（更新满足条件的1个或多个记录）
        /// </summary>
        /// <param name="oldSqlTableEntry">满足实例的条件</param>
        /// <param name="newSqlTableEntry">新实例的值</param>
        /// <param name="SharedOpenConnection">已打开的共享数据库连接，只使用不关闭及销毁。</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int ReplaceWith(this TableEntry oldSqlTableEntry, TableEntry newSqlTableEntry, DbConnection SharedOpenConnection)
        {
            return ReplaceWith(oldSqlTableEntry, newSqlTableEntry, SharedOpenConnection, null);
        }

        /// <summary>
        /// (忽略主键)依据旧有实例属性替换为新实例属性的值（更新满足条件的1个或多个记录）
        /// </summary>
        /// <param name="oldSqlTableEntry">满足实例的条件</param>
        /// <param name="newSqlTableEntry">新实例的值</param>
        /// <returns>返回受影响的记录条数</returns>
        public static int ReplaceWith(this TableEntry oldSqlTableEntry, TableEntry newSqlTableEntry)
        {
            return ReplaceWith(oldSqlTableEntry, newSqlTableEntry, null, null);
        }

        #endregion
	}
}
